package com.iyunwen.datatool.dataanalysis.impl;

import com.iyunwen.datatool.common.annotations.EventTypeAnnotation;
import com.iyunwen.datatool.common.enums.DataSourceTypeEnum;
import com.iyunwen.datatool.dataanalysis.DataAnalysis;
import com.iyunwen.datatool.dataexport.DataExport;
import com.iyunwen.datatool.model.dbdo.EventDataDO;
import com.iyunwen.datatool.model.vo.DataGroupVO;
import com.iyunwen.datatool.utils.MD5Utils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import java.text.SimpleDateFormat;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * @description:
 * @author: Zhu.Guodong
 * @create: 2020-03-20 10:27
 * @version:
 */
@Slf4j
@Component
@EventTypeAnnotation(eventType = DataSourceTypeEnum.EVENT_LOG)
public class EventLogDataAnalysisImpl implements DataAnalysis<EventDataDO> {

    private long RANGE_TIME = 5000L;

    /**
     * 高等级
     */
    private String[] LEVEL_KEY_WORD = {"紧急/故障", "警告"};

    private static final Pattern[] patterns = {
            Pattern.compile(".*闭锁.*"),
            Pattern.compile(".*跳闸.*"),
//            Pattern.compile(".*故障(?!录波).*"),
            Pattern.compile(".*ESOF.*"),
//            Pattern.compile(".*异常.*"),
            Pattern.compile(".*禁止.*"),
            Pattern.compile(".*切换.*系统.*"),
            Pattern.compile(".*冗余耗尽.*"),
            Pattern.compile(".*强制移相.*"),
            Pattern.compile(".*另一系统正常.*"),
            Pattern.compile(".*脉冲.*"),
            Pattern.compile(".*VBE.*"),
    };
//    /**
//     * 匹配关键词
//     */
//    private String[] MATCH_KEY_REGEX = {
//            ".*闭锁.*",
//            ".*跳闸.*",
//            ".*故障.*",
//            ".*ESOF.*",
//            ".*异常.*",
//            ".*禁止.*",
//            ".*切换.*系统.*",
//            ".*冗余耗尽.*",
//            ".*强制移相.*",
//            ".*另一系统正常.*",
//            ".*脉冲.*",
//            ".*VBE.*",
//    };

    /**
     * 事件状态
     */
    String[] EVENT_STATUS = {"产生", "消失"};

    private boolean isHighLevel(EventDataDO eventDataDO) {
        //事件等级
        String eventLevel = eventDataDO.getEventLevel();
        List<String> highLevels = Arrays.asList(LEVEL_KEY_WORD);
        boolean contains = highLevels.contains(eventLevel);
        return contains;
    }

    public boolean isAttentionSignal(EventDataDO eventDataDO) {
        boolean isHighLevel = isHighLevel(eventDataDO);
        if (isHighLevel) {
            for (Pattern pattern : patterns) {
                //事件描述
                String eventDesc = eventDataDO.getEventDesc();
                Matcher matcher = pattern.matcher(eventDesc);
                boolean matches = matcher.matches();
                if (matches) {
                    return true;
                }

            }
        }
        return false;
    }

    public String getAttentionSignalKeyWord(EventDataDO eventDataDO) {
        for (Pattern pattern : patterns) {
            //事件描述
            String eventDesc = eventDataDO.getEventDesc();
            Matcher matcher = pattern.matcher(eventDesc);
            boolean matches = matcher.matches();
            if (matches) {
                return pattern.pattern().replaceAll("\\.\\*", "").replaceAll("\\?", "");
            }

        }
        return "无关键词匹配";
    }

    public DataGroupVO getGroupByIndex(List<EventDataDO> dataList, int index) {
        //分组数据集合
        List<EventDataDO> groupDataList = new LinkedList<>();
        List<EventDataDO> sourceEventDataList = new ArrayList<>();

        EventDataDO eventDataDO = dataList.get(index);
        long time = eventDataDO.getEventTime();
        String eventStatus = eventDataDO.getEventStatus();
        String eventSource = eventDataDO.getEventSource();

        //产生消失状态的记录
        boolean eventStatusFlag = false;
        if ("产生".equalsIgnoreCase(eventStatus)) {
            eventStatusFlag = true;
        }

        //向前找
        ListIterator<EventDataDO> preIterator = dataList.listIterator(index);
        while (preIterator.hasPrevious()) {
            EventDataDO item = preIterator.previous();
            long itemTime = item.getEventTime();
            long itemRangeTime = Math.abs(time - itemTime);
            if (itemRangeTime > RANGE_TIME) {
                break;
            }
            boolean highLevel = isHighLevel(item);
            String itemStatus = item.getEventStatus();
            String eventDesc = item.getEventDesc();

            boolean addFlag = highLevel && eventSource.equalsIgnoreCase(item.getEventSource());
            ; //|| (eventStatusFlag && "消失".equalsIgnoreCase(itemStatus) && eventDesc.equalsIgnoreCase(eventDataDO.getEventDesc()));
            if (addFlag) {
                //item.getGroupIdSet().add(index);
                item.setGroupFlag(true);
                sourceEventDataList.add(item);
                EventDataDO eventDataCache = getEventDataCache(item);
                if (!groupDataList.contains(eventDataCache)) {
                    groupDataList.add(eventDataCache);
                }
            }

        }
        Collections.reverse(sourceEventDataList);
        Collections.reverse(groupDataList);

        //向后找
        ListIterator<EventDataDO> nextIterator = dataList.listIterator(index);
        while (nextIterator.hasNext()) {
            EventDataDO item = nextIterator.next();

            long itemTime = item.getEventTime();
            long itemRangeTime = Math.abs(itemTime - time);
            if (itemRangeTime > RANGE_TIME) {
                break;
            }
            boolean highLevel = isHighLevel(item);
            String itemStatus = item.getEventStatus();
            String eventDesc = item.getEventDesc();

            boolean addFlag = highLevel && eventSource.equalsIgnoreCase(item.getEventSource());//|| (eventStatusFlag && "消失".equalsIgnoreCase(itemStatus) && eventDesc.equalsIgnoreCase(eventDataDO.getEventDesc()));
            if (addFlag) {
                //item.getGroupIdSet().add(index);
                item.setGroupFlag(true);
                sourceEventDataList.add(item);
                EventDataDO eventDataCache = getEventDataCache(item);
                if (!groupDataList.contains(eventDataCache)) {
                    groupDataList.add(eventDataCache);
                }
            }
        }

        //排序
        Collections.sort(groupDataList, new Comparator<EventDataDO>() {

            @Override
            public int compare(EventDataDO o1, EventDataDO o2) {
                String temp1 = o1.getDataUniqSFlag();
                String temp2 = o2.getDataUniqSFlag();
                return temp1.compareTo(temp2);
            }

        });
        DataGroupVO dataGroupVO = new DataGroupVO();
        dataGroupVO.setFlagIndex(index);
        dataGroupVO.setEventData(groupDataList);
//        dataGroupVO.setEventCnt(groupDataList.size());
//        dataGroupVO.setSourceDateMatchCnt(1);
        List<List<EventDataDO>> eventDataListTemp = new LinkedList<>();
        eventDataListTemp.add(sourceEventDataList);
        dataGroupVO.setSourceEventData(eventDataListTemp);

        return dataGroupVO;
    }

    Map<String, EventDataDO> eventDataCache = new HashMap<>();

    private EventDataDO getEventDataCache(EventDataDO eventDataDO) {
        String dataUniqSFlag = eventDataDO.getDataUniqSFlag();
        if (!eventDataCache.containsKey(dataUniqSFlag)) {
            EventDataDO newUniqBaseData = eventDataDO.getNewUniqBaseData();
            eventDataCache.put(dataUniqSFlag, newUniqBaseData);
        }
        return eventDataCache.get(dataUniqSFlag);
    }

    @Override
    public List<DataGroupVO> analyzeDataToGroup(List<EventDataDO> dataList) {

        List<DataGroupVO> groupResultList = new LinkedList<>();

        Map<String, DataGroupVO> groupFlagTempMap = new HashMap<>();

        int groupIndex = 0;
        int dataIndex = 0;
        Iterator<EventDataDO> iterator = dataList.iterator();
        while (iterator.hasNext()) {
            int itemIndex = dataIndex;
            dataIndex++;

            //当前遍历的事件
            EventDataDO eventDataDO = iterator.next();
            //是否是重点关注数据
            boolean attentionSignal = isAttentionSignal(eventDataDO);
            String attentionSignalKeyWord = getAttentionSignalKeyWord(eventDataDO);


            if (attentionSignal) {
                //log.info("分组组合下标:{}", itemIndex);
                long startTime = System.currentTimeMillis();
                DataGroupVO groupByIndex = getGroupByIndex(dataList, itemIndex);
                if (null != groupByIndex) {
                    //和上一个比较是否相同
                    String groupUniqFlag = groupByIndex.getGroupUniqFlag();
                    if (groupFlagTempMap.containsKey(groupUniqFlag)) {
                        DataGroupVO dataGroupTemp = groupFlagTempMap.get(groupUniqFlag);
                        String groupName = dataGroupTemp.getGroupName();
                        //是否已经包含该关键字或者名称过长
                        if (!groupName.contains(attentionSignalKeyWord) && groupName.length() < 30) {
                            groupName = groupName + "_" + attentionSignalKeyWord;
                            dataGroupTemp.setGroupName(groupName);
                        }
                        //匹配分组数据量
//                        int sourceDateMatchCnt = groupByIndex.getSourceDateMatchCnt() + dataGroupTemp.getSourceDateMatchCnt();
//                        dataGroupTemp.setSourceDateMatchCnt(sourceDateMatchCnt);
                        //匹配分组数据，去重
                        List<List<EventDataDO>> eventDataListTemp = dataGroupTemp.getSourceEventData();
                        List<List<EventDataDO>> sourceEventData = groupByIndex.getSourceEventData();
                        Set<String> uniqFlagSet = new HashSet<>();
                        for (List<EventDataDO> sourceEventDatum : eventDataListTemp) {
                            String dataListUniqFlag = getDataListUniqFlag(sourceEventDatum);
                            uniqFlagSet.add(dataListUniqFlag);
                        }
                        for (List<EventDataDO> eventDataDOList : sourceEventData) {
                            String dataListUniqFlag = getDataListUniqFlag(eventDataDOList);
                            if (!uniqFlagSet.contains(dataListUniqFlag)) {
                                eventDataListTemp.add(eventDataDOList);
                            }
                        }
                        //eventDataListTemp.addAll(sourceEventData);
                        continue;
                    }

                    //分组唯一标识添加
                    groupFlagTempMap.put(groupUniqFlag, groupByIndex);
                    groupByIndex.setIndex(groupIndex);
                    //groupByIndex.setGroupName("异常事件日志分组" + (groupIndex + 1));
                    groupByIndex.setGroupName((groupIndex + 1) + "_" + attentionSignalKeyWord);
                    //和上一个分组不同
                    groupResultList.add(groupByIndex);
                    //导出
                    //dataExport.dataExportToFile(groupByIndex);
                    groupIndex++;
                }
                log.info("数据下标:{},分组下标:{},分组事件数据量:{},分组耗时:{}", itemIndex, groupIndex, groupByIndex.getEventData().size(), System.currentTimeMillis() - startTime);

            }
        }


        return groupResultList;
    }

    private String getDataListUniqFlag(List<EventDataDO> eventDataDOS) {
        StringBuilder sb = new StringBuilder();
        for (EventDataDO eventDataDO : eventDataDOS) {
            int code = eventDataDO.hashCode();
            sb.append(code);
        }
        String md5 = MD5Utils.MD5(sb.toString(), 32);
        return md5;
    }


    @Override
    public List<DataGroupVO> analyzeDataToGroup(List<EventDataDO> dataList, DataExport dataExport) {

        //Map<String, DataGroupVO> groupFlagTempSet = new HashMap<>();

        List<DataGroupVO> groupResultList = new LinkedList<>();
        int groupIndex = 0;


        int dataIndex = 0;
        SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmm");
        String dayTimeTemp = "";
        String dayTimeNow = "";
        //根据日期缓存
        Map<String, Map<String, DataGroupVO>> groupCacheByTime = new HashMap<>();
        for (EventDataDO eventDataDO : dataList) {
            int i = dataIndex;
            dataIndex++;

            //Timestamp eventTime = eventDataDO.getEventTime();
            Date eventTime = new Date(eventDataDO.getEventTime());
            String nowDate = sdf.format(eventTime);

            if (dayTimeTemp.length() == 0 && dayTimeNow.length() == 0) {
                //初始化
                dayTimeTemp = nowDate;
                dayTimeNow = nowDate;
            }
            if (!dayTimeNow.equals(nowDate)) {
                //缓存日期和当前日期不同
                if (!dayTimeTemp.equals(dayTimeNow)) {
                    groupCacheByTime.remove(dayTimeTemp);
                }
                dayTimeTemp = dayTimeNow;
                dayTimeNow = nowDate;
            }
            if (!groupCacheByTime.containsKey(nowDate)) {
                Map<String, DataGroupVO> groupFlagTempMap = new HashMap<>();
                groupCacheByTime.put(nowDate, groupFlagTempMap);
            }

            //是否是重点关注数据
            boolean attentionSignal = isAttentionSignal(eventDataDO);
            String attentionSignalKeyWord = getAttentionSignalKeyWord(eventDataDO);


            if (attentionSignal) {
                log.info("分组组合下标:{}", i);
                long startTime = System.currentTimeMillis();
                DataGroupVO groupByIndex = getGroupByIndex(dataList, i);
                if (null != groupByIndex) {
                    //和上一个比较是否相同
                    String groupUniqFlag = groupByIndex.getGroupUniqFlag();
                    Map<String, DataGroupVO> groupFlagTempMap = groupCacheByTime.get(nowDate);
                    if (groupFlagTempMap.containsKey(groupUniqFlag)) {
                        DataGroupVO dataGroupTemp = groupFlagTempMap.get(groupUniqFlag);
                        String groupName = dataGroupTemp.getGroupName();
                        if (!groupName.contains(attentionSignalKeyWord)) {
                            groupName = groupName + "_" + attentionSignalKeyWord;
                            dataGroupTemp.setGroupName(groupName);
                        }
                        continue;
                    }
                    groupFlagTempMap.put(groupUniqFlag, groupByIndex);
                    groupByIndex.setIndex(groupIndex);
                    //groupByIndex.setGroupName("异常事件日志分组" + (groupIndex + 1));
                    groupByIndex.setGroupName((groupIndex + 1) + attentionSignalKeyWord);
                    //和上一个分组不同
                    groupResultList.add(groupByIndex);
                    //导出
                    dataExport.dataExportToFile(groupByIndex);
                    groupIndex++;
                }
                log.info("数据下标:{},分组下标:{},分组数据量:{},分组耗时:{}", i, groupIndex, groupByIndex.getEventData().size(), System.currentTimeMillis() - startTime);

            }
        }

//        log.info("无分组高等级数据分组组合开始...");
//        long groupStartTime = System.currentTimeMillis();
//        //分组数据集合
//        List<BaseNormalizationDataVO> groupDataList = new LinkedList<>();
//
//        for (EventDataDO eventDataDO : dataList) {
//            boolean groupFlag = eventDataDO.isGroupFlag();
//            if (!groupFlag) {
//                boolean highLevel = isHighLevel(eventDataDO);
//                if (highLevel) {
//                    groupDataList.add(eventDataDO);
//
//                }
//            }
//        }
//        DataGroupVO eventGroupVO = new DataGroupVO();
//        eventGroupVO.setEventData(groupDataList);
//        eventGroupVO.setIndex(groupIndex);
//        eventGroupVO.setGroupName("无分组高等级数据");
//        //导出
//        dataExport.dataExportToFile(eventGroupVO);
//        groupResultList.add(eventGroupVO);
//        log.info("无分组高等级数据,分组数据量:{},分组耗时:{}", groupDataList.size(), System.currentTimeMillis() - groupStartTime);

        return groupResultList;
    }
}
